package cDB

import (
	"fmt"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type GormBuilder struct {
	Conditions map[string]any
	Page       int64
	Size       int64
	OrderBy    string
	GroupBy    string
}

type Model[T ModelInterface] struct{}

// Create 添加单条数据
func (i Model[T]) Create(ctx *gin.Context, data T) (err error) {
	ptr := new(T)
	err = WithContextModel(ctx, *ptr).Create(data).Error
	return
}

// Save 根据主键更新或新增数据
func (i Model[T]) Save(ctx *gin.Context, data T) (err error) {
	ptr := new(T)
	err = WithContextTable(ctx, *ptr).Save(data).Error
	return
}

// FirstOrCreate 查找或新增单条数据
func (i Model[T]) FirstOrCreate(ctx *gin.Context, data T, conditions map[string]any) (created int64, err error) {
	ptr := new(T)
	result := WithContextModel(ctx, *ptr).FirstOrCreate(data, conditions)
	return result.RowsAffected, result.Error
}

// Insert 批量添加数据
func (i Model[T]) Insert(ctx *gin.Context, data []T) (err error) {
	ptr := new(T)
	err = WithContextModel(ctx, *ptr).CreateInBatches(data, 1000).Error
	return
}

// InsertOrIgnore 批量添加数据，存在则忽略
func (i Model[T]) InsertOrIgnore(ctx *gin.Context, data []T, fields []string) (err error) {
	columns := []clause.Column{}
	for _, field := range fields {
		columns = append(columns, clause.Column{Name: field})
	}
	ptr := new(T)
	err = WithContextModel(ctx, *ptr).Clauses(clause.OnConflict{
		Columns:   columns,
		DoNothing: true,
	}).CreateInBatches(data, 1000).Error
	return
}

// InsertOrUpdate 批量添加数据，存在则更新
func (i Model[T]) InsertOrUpdate(ctx *gin.Context, data []T, fields []string) (err error) {
	columns := []clause.Column{}
	for _, field := range fields {
		columns = append(columns, clause.Column{Name: field})
	}
	ptr := new(T)
	err = WithContextModel(ctx, *ptr).Clauses(clause.OnConflict{
		Columns:   columns,
		UpdateAll: true,
	}).CreateInBatches(data, 1000).Error
	return
}

// UpdateOrCreate 更新或新建单条数据，必须要有唯一索引才生效
func (i Model[T]) UpdateOrCreate(ctx *gin.Context, data T, fields []string) (err error) {
	columns := []clause.Column{}
	for _, field := range fields {
		columns = append(columns, clause.Column{Name: field})
	}

	ptr := new(T)
	err = WithContextModel(ctx, *ptr).Clauses(clause.OnConflict{
		Columns:   columns,
		UpdateAll: true,
	}).Create(data).Error
	return
}

// CreateOrIgnore 新建单条数据或忽略，必须要有唯一索引才生效
func (i Model[T]) CreateOrIgnore(ctx *gin.Context, data T, fields []string) (err error) {
	columns := []clause.Column{}
	for _, field := range fields {
		columns = append(columns, clause.Column{Name: field})
	}

	ptr := new(T)
	err = WithContextModel(ctx, *ptr).Clauses(clause.OnConflict{
		Columns:   columns,
		DoNothing: true,
	}).Create(data).Error
	return
}

// FindByConditions 根据条件查询单条数据
func (i Model[T]) FindByConditions(ctx *gin.Context, conditions map[string]any) (result T, err error) {
	if len(conditions) == 0 {
		return
	}
	ptr := new(T)
	query := WithContextModel(ctx, *ptr)
	for k, v := range conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.First(ptr).Error
	if err != nil {
		return
	}

	result = *ptr

	return
}

// GetByConditions 根据条件查询多条数据，条件不存在则查询所有数据
func (i Model[T]) GetByConditions(ctx *gin.Context, conditions map[string]any) (result []T, err error) {
	result = make([]T, 0)
	ptr := new(T)
	query := WithContextModel(ctx, *ptr)

	for k, v := range conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.Find(&result).Error

	return
}

// GetByConditions 根据条件查询多条数据，条件不存在则查询所有数据
func (i Model[T]) GetByBuilder(ctx *gin.Context, builder GormBuilder) (result []T, err error) {
	result = make([]T, 0)
	ptr := new(T)
	query := WithContextModel(ctx, *ptr)

	for k, v := range builder.Conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	if builder.OrderBy != "" {
		query = query.Order(builder.OrderBy)
	}

	err = query.Find(&result).Error

	return
}

// CountByConditions 根据条件统计数量
func (i Model[T]) CountByConditions(ctx *gin.Context, conditions map[string]any) (total int64, err error) {
	total = 0
	ptr := new(T)
	query := WithContextModel(ctx, *ptr)

	for k, v := range conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.Count(&total).Error

	return
}

// ListByConditions 根据条件分页查询
func (i Model[T]) ListByConditions(ctx *gin.Context, conditions map[string]any, page, size int64, order string) (result []T, err error) {
	result = make([]T, 0)

	if page < 1 {
		page = 1
	}
	if size < 1 {
		size = 0
	}
	offset := int((page - 1) * size)

	ptr := new(T)
	query := WithContextModel(ctx, *ptr)
	if size > 0 {
		query = query.Offset(offset).Limit(int(size))
	}

	if order != "" {
		query = query.Order(order)
	}

	for k, v := range conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.Find(&result).Error

	return
}

// ListByBuilder 根据构造器查询
func (i Model[T]) ListByBuilder(ctx *gin.Context, builder GormBuilder) (result []T, err error) {
	result = make([]T, 0)

	if builder.Page < 1 {
		builder.Page = 1
	}
	if builder.Size < 1 {
		builder.Size = 0
	}
	offset := int((builder.Page - 1) * builder.Size)

	ptr := new(T)
	query := WithContextModel(ctx, *ptr)
	if builder.Size > 0 {
		query = query.Offset(offset).Limit(int(builder.Size))
	}

	if builder.OrderBy != "" {
		query = query.Order(builder.OrderBy)
	}

	for k, v := range builder.Conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.Find(&result).Error

	return
}

// UpdateByConditions 根据条件更新数据
func (i Model[T]) UpdateByConditions(ctx *gin.Context, conditions map[string]any, fields map[string]any) (err error) {
	ptr := new(T)
	query := WithContextModel(ctx, *ptr)
	for k, v := range conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.Updates(fields).Error

	return
}

// DeleteByConditions 根据条件删除数据
func (i Model[T]) DeleteByConditions(ctx *gin.Context, conditions map[string]any) (err error) {
	ptr := new(T)
	query := WithContextModel(ctx, *ptr)
	for k, v := range conditions {
		switch value := v.(type) {
		case []any:
			query = query.Where(k, value...)
		default:
			query = query.Where(k, v)
		}
	}

	err = query.Delete([]T{}).Error

	return
}

func (i Model[T]) StartTransaction(ctx *gin.Context, f func(ctx *gin.Context, tx *gorm.DB) (err error)) (err error) {
	ptr := new(T)
	err = StartTransactionWithModel(ctx, *ptr, f)

	return
}

func (i Model[T]) Truncate(ctx *gin.Context) (err error) {
	ptr := new(T)
	table := (*ptr).TableName()

	err = WithContextTable(ctx, *ptr).Exec(fmt.Sprintf("TRUNCATE TABLE %s", table)).Error

	return
}
